package com.egghiro.framework.j2se.game.core.timer;

public class SystemTimer {

    private Thread granularityThread;

    private long lastTime;

    private long virtualTime;

    private boolean running = false;

    public void start() {
        lastTime = System.currentTimeMillis();
        virtualTime = 0;
        running = true;
    }

    public void stop() {
        running = false;
        setHighSleepGranularity(false);
    }

    private final boolean getHighSleepGranularity() {
        return (granularityThread != null && granularityThread.isAlive());
    }

    private void setHighSleepGranularity(boolean high) {
        if (high != getHighSleepGranularity()) {
            if (high) {
                startGranularityThread();
            } else {
                stopGranularityThread();
            }
        }
    }

    private final synchronized void startGranularityThread() {
        Thread t = new Thread() {
            public void run() {
                while (granularityThread == this && running) {
                    try {
                        Thread.sleep(Integer.MAX_VALUE);
                    } catch (InterruptedException ex) {
                    }
                }
            }
        };
        t.setDaemon(true);
        try {
            t.start();
        } catch (IllegalThreadStateException ex) {
            t = null;
        }
        granularityThread = t;
    }

    private final synchronized void stopGranularityThread() {
        if (granularityThread != null) {
            Thread t = granularityThread;
            granularityThread = null;
            if (t.isAlive()) {
                try {
                    t.interrupt();
                } catch (Exception ex) {
                    granularityThread = t;
                }
            }
        }
    }

    public long sleepTimeMicros(long goalTimeMicros) {
        return sleepTimeMicros(goalTimeMicros, this);
    }

    public static long sleepTimeMicros(long goalTimeMicros, SystemTimer timer) {
        long time = goalTimeMicros - timer.getTimeMicros();
        if (time >= 500) {
            try {
                Thread.sleep((int) ((time + 500) / 1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return timer.getTimeMicros();
    }

    public long getTimeMillis() {
        long time = System.currentTimeMillis();
        if (time > lastTime) {
            virtualTime += time - lastTime;
        }
        lastTime = time;

        return virtualTime;
    }

    public long getTimeMicros() {
        return getTimeMillis() * 1000;
    }

}
